/*
 * VHClubMatchesGrid.java
 * Created on 23 sept. 2009
 *
 * VirtualHockey Internet Platform
 * http://code.google.com/p/virtualhockey/
 *
 * Copyright (c) 2005-2009, Jens and Jan Janke (VirtualHockey Project)
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program. If not, see http://www.gnu.org/licenses/.
 */

package com.hockeo.vhweb.client.ui.widget;

import java.util.ArrayList;
import java.util.List;

import com.extjs.gxt.ui.client.Style.HorizontalAlignment;
import com.extjs.gxt.ui.client.Style.SortDir;
import com.extjs.gxt.ui.client.store.GroupingStore;
import com.extjs.gxt.ui.client.store.ListStore;
import com.extjs.gxt.ui.client.widget.LayoutContainer;
import com.extjs.gxt.ui.client.widget.grid.ColumnConfig;
import com.extjs.gxt.ui.client.widget.grid.ColumnData;
import com.extjs.gxt.ui.client.widget.grid.ColumnModel;
import com.extjs.gxt.ui.client.widget.grid.Grid;
import com.extjs.gxt.ui.client.widget.grid.GridCellRenderer;
import com.extjs.gxt.ui.client.widget.grid.GridGroupRenderer;
import com.extjs.gxt.ui.client.widget.grid.GroupColumnData;
import com.extjs.gxt.ui.client.widget.grid.GroupingView;
import com.extjs.gxt.ui.client.widget.grid.RowNumberer;
import com.extjs.gxt.ui.client.widget.layout.FitLayout;
import com.google.gwt.user.client.Window;
import com.hockeo.vhweb.client.VHMain;
import com.hockeo.vhweb.client.mvc.VHController;
import com.hockeo.vhweb.client.res.VHResConstants;
import com.hockeo.vhweb.client.res.VHResMessages;
import com.hockeo.vhweb.client.rpc.VHRpcResultReceiver;
import com.hockeo.vhweb.client.ui.menu.VHClubInfoContextMenu;
import com.hockeo.vhweb.client.ui.menu.VHGridContextMenu;
import com.hockeo.vhweb.client.utils.VHJsData;
import com.hockeo.vhweb.client.utils.enums.VHJsContestType;
import com.hockeo.vhweb.client.utils.enums.VHJsMatchResultType;
import com.hockeo.vhweb.client.utils.enums.VHJsMatchType;
import com.hockeo.vhweb.client.utils.enums.VHJsMatchlistGroupingType;

/**
 * Represents a grid that displays the matches for one particular club.
 *
 * @version $Id$
 * @author jjanke
 */
public class VHClubMatchesGrid extends LayoutContainer implements VHRpcResultReceiver<List<VHJsData>>
{
  private static final String           COL_MATCH_ORDER         = "match_order";
  private static final String           COL_RESULT_TYPE         = "result_type";
  private static final String           COL_MATCHDAY_MOVEDAY_ID = "matchday_moveday_id";
  private static final String           COL_MATCH_TYPE          = "match_type";
  private static final String           COL_CONTEST_TYPE_ORDER  = "contest_type_order";
  private static final String           COL_CONTEST_TYPE        = "contest_type";

  private final VHGridContextMenu       d_ctxmenu;
  private List<VHJsData>                d_listMatches;
  private final GroupingStore<VHJsData> d_store;
  private Grid<VHJsData>                d_grid;
  private VHJsData                      d_club;
  private VHJsMatchlistGroupingType     d_grouping;
  private VHJsMatchType                 d_matchType;

  /**
   * Builds a new match grid for the given club.
   *
   * @param club the club for which to display the matches
   * @param grouping initial grouping type
   * @param matchType the initial match type
   */
  public VHClubMatchesGrid( VHController controller, VHJsData club, VHJsMatchlistGroupingType grouping,
                            VHJsMatchType matchType )
  {
    d_store = new GroupingStore<VHJsData>();
    setClub( club );
    setGrouping( grouping );
    setMatchType( matchType );

    buildGrid();
    setLayout( new FitLayout() );
    add( d_grid );

    d_ctxmenu = new VHClubInfoContextMenu( controller, d_grid, "clubOpponent_" );
  }

  public void setRpcData( List<VHJsData> listMatches, String strPurpose )
  {
    // Reinit internal state
    //
    if ( d_listMatches == null )
      d_listMatches = new ArrayList<VHJsData>();
    else
      d_listMatches.clear();

    d_store.removeAll();

    // Iterate over all matches, throw out not required matches and do not add either the
    // home or away matches to the store if a match type not equaling ALL is selected.
    //
    for ( VHJsData match : listMatches )
    {
      // skip not required matches
      //
      if ( match.getBoolean( "notRequired" ) )
        continue;

      // add information about the contest type (league, cup, cl or wl)
      //
      String strContestId = match.getString( "matchday_contestElement_contest_id" );
      if ( strContestId.equals( "EU1" ) )
      {
        match.set( COL_CONTEST_TYPE, VHJsContestType.CL.name() );
        match.set( COL_CONTEST_TYPE_ORDER, VHJsContestType.CL.ordinal() );
      }
      else if ( strContestId.equals( "EU2" ) )
      {
        match.set( COL_CONTEST_TYPE, VHJsContestType.WL.name() );
        match.set( COL_CONTEST_TYPE_ORDER, VHJsContestType.WL.ordinal() );
      }
      else if ( strContestId.equals( d_club.get( "league_id" ) ) )
      {
        match.set( COL_CONTEST_TYPE, VHJsContestType.LEAGUE.name() );
        match.set( COL_CONTEST_TYPE_ORDER, VHJsContestType.LEAGUE.ordinal() );
      }
      else
      {
        match.set( COL_CONTEST_TYPE, VHJsContestType.CUP.name() );
        match.set( COL_CONTEST_TYPE_ORDER, VHJsContestType.CUP.ordinal() );
      }

      // add information about match type (home or away)
      //
      if ( match.get( "clubHome_id" ).equals( d_club.getId() ) )
      {
        match.set( COL_MATCH_TYPE, VHJsMatchType.HOME.name() );

        match.renamePropertiesWithPrefix( "clubHome", "clubThis" );
        match.renamePropertiesWithPrefix( "clubAway", "clubOpponent" );

        match.renameProperty( "costHome", "costThis" );
        match.renameProperty( "costAway", "costOpponent" );

        match.renameProperty( "goalsHome", "goalsThis" );
        match.renameProperty( "goalsAway", "goalsOpponent" );

        match.renameProperty( "goalsShootoutHome", "goalsShootoutThis" );
        match.renameProperty( "goalsShootoutAway", "goalsShootoutOpponent" );
      }
      else
      {
        match.set( COL_MATCH_TYPE, VHJsMatchType.AWAY.name() );

        match.renamePropertiesWithPrefix( "clubAway", "clubThis" );
        match.renamePropertiesWithPrefix( "clubHome", "clubOpponent" );

        match.renameProperty( "costAway", "costThis" );
        match.renameProperty( "costHome", "costOpponent" );

        match.renameProperty( "goalsAway", "goalsThis" );
        match.renameProperty( "goalsHome", "goalsOpponent" );

        match.renameProperty( "goalsShootoutAway", "goalsShootoutThis" );
        match.renameProperty( "goalsShootoutHome", "goalsShootoutOpponent" );
      }

      // add information about the match result
      //
      if ( !match.getBoolean( "played" ) )
        match.set( COL_RESULT_TYPE, VHJsMatchResultType.NOT_PLAYED.name() );
      else if ( match.getString( "winner_id" ).equals( d_club.getId() ) )
        match.set( COL_RESULT_TYPE, VHJsMatchResultType.VICTORY.name() );
      else
        match.set( COL_RESULT_TYPE, VHJsMatchResultType.LOSS.name() );

      // add column for ordering
      //
      String strMatchday = String.valueOf( match.getInt( "matchday_num" ) );
      if ( strMatchday.length() == 1 )
        strMatchday = "0" + strMatchday;
      match.set( COL_MATCH_ORDER, match.getInt( COL_CONTEST_TYPE_ORDER ) + "_" + strMatchday );

      // add to the internal list of matches and to the store if the match type matches
      //
      d_listMatches.add( match );

      if ( d_matchType == VHJsMatchType.ALL || d_matchType.name().equals( match.getString( COL_MATCH_TYPE ) ) )
        d_store.add( match );
    }

    // grouping and ordering
    //
    groupStore();
  }

  /**
   * Empties the data store and sets the club to the given value.
   *
   * @param club the new club to be set
   */
  public void setClub( VHJsData club )
  {
    if ( d_club != null && d_club.getId().equals( club.getId() ) )
      return;

    d_club = club;
    d_store.removeAll();
  }

  /**
   * Resets the grouping.
   *
   * @param grouping the new match list grouping
   */
  public void setGrouping( VHJsMatchlistGroupingType grouping )
  {
    if ( d_grouping != null && d_grouping == grouping )
      return;

    d_grouping = grouping;

    if ( !d_store.getModels().isEmpty() )
      groupStore();
  }

  /**
   * Groups the data in the underlying store according to the set grouping preference.
   */
  private void groupStore()
  {
    // grouping
    //
    switch ( d_grouping )
    {
      case BY_CONTEST_TYPE:
        d_store.groupBy( COL_CONTEST_TYPE_ORDER );
        break;

      case BY_MOVEDAY:
        d_store.groupBy( COL_MATCHDAY_MOVEDAY_ID );
        break;

      default:
        Window.alert( "Unsupported grouping type: " + d_grouping.name() );
    }

    // ordering
    //
    d_store.sort( COL_MATCH_ORDER, SortDir.ASC );
  }

  /**
   * Resets the match type.
   *
   * @param matchType the match type to be set
   */
  public void setMatchType( VHJsMatchType matchType )
  {
    if ( d_matchType != null && d_matchType == matchType )
      return;

    d_matchType = matchType;

    if ( d_store.getModels().isEmpty() )
      return;

    // reinit the store
    //
    d_store.removeAll();
    for ( VHJsData match : d_listMatches )
    {
      if ( d_matchType == VHJsMatchType.ALL || d_matchType.name().equals( match.getString( COL_MATCH_TYPE ) ) )
        d_store.add( match );
    }

    groupStore();
  }

  private void buildGrid()
  {
    final VHResConstants constants = VHMain.getConstants();
    final VHResMessages messages = VHMain.getMessages();

    // Cell rendering
    //
    GridCellRenderer<VHJsData> renderer = new GridCellRenderer<VHJsData>() {
      public String render( VHJsData m, String strProperty, ColumnData config, int rowIndex, int colIndex,
          ListStore<VHJsData> store, Grid<VHJsData> grid )
      {
        if ( strProperty.equals( COL_RESULT_TYPE ) )
        {
          String strIcon;
          VHJsMatchResultType result = VHJsMatchResultType.valueOf( m.getString( strProperty ) );

          switch ( result )
          {
            case LOSS:
              strIcon = "relegated";
              break;

            case VICTORY:
              strIcon = "promoted";
              break;

            case NOT_PLAYED:
              strIcon = "midfield";
              break;

            default:
              strIcon = "midfield";
          }

          return "<img src='images/picto/rank_" + strIcon + ".gif'/>";
        }
        else if ( strProperty.equals( COL_MATCH_ORDER ) )
          return String.valueOf( m.getInt( "matchday_num" ) );
        else if ( strProperty.equals( COL_CONTEST_TYPE ) )
          return "<img src='images/contests/" + m.getString( strProperty ).toLowerCase() + "_16.png'/>";
        else if ( strProperty.equals( COL_MATCH_TYPE ) )
          return "<img src='images/picto/match_" + m.getString( strProperty ).toLowerCase() + ".png'/>";
        else if ( strProperty.equals( "clubOpponent_country" ) )
        {
          String strTooltip = m.getString( "clubOpponent_country_name" );

          return "<img src='images/flags/16x16/" + m.getString( strProperty ) + ".png' title='" + strTooltip + "'/>";
        }
        else if ( strProperty.equals( "clubOpponent_name" ) )
        {
          String strClubName = m.getString( strProperty );
          VHJsMatchResultType result = VHJsMatchResultType.valueOf( m.getString( COL_RESULT_TYPE ) );

          // show league category
          //
          strClubName += " (" + m.getInt( "clubOpponent_league_category" ) + ")";

          switch ( result )
          {
            case LOSS:
              strClubName = "<span style='color: red;'>" + strClubName + "</span>";
              break;

            case VICTORY:
              strClubName = "<span style='color: green;'>" + strClubName + "</span>";
              break;
          }

          return strClubName;
        }
        else if ( strProperty.equals( "goalsThis" ) )
        {
          if ( !m.getBoolean( "played" ) )
            return constants.matchGoalsNotPlayed();

          String strResult = m.getInt( "goalsThis" ) + constants.matchGoalsSeparator() + m.getInt( "goalsOpponent" );
          VHJsMatchResultType result = VHJsMatchResultType.valueOf( m.getString( COL_RESULT_TYPE ) );

          if ( m.getBoolean( "decidedByShootout" ) )
            strResult += " <span title='" + constants.afterShootoutToolTip() + "'>(" + m.getInt( "goalsShootoutThis" )
                + constants.matchGoalsSeparator() + m.getInt( "goalsShootoutOpponent" ) + ") "
                + constants.afterShootout() + "</span>";

          switch ( result )
          {
            case LOSS:
              strResult = "<span style='color: red;'>" + strResult + "</span>";
              break;

            case VICTORY:
              strResult = "<span style='color: green;'>" + strResult + "</span>";
              break;
          }

          return strResult;
        }

        return String.valueOf( m.get( strProperty ) );
      }
    };

    // Column definitions
    //
    ArrayList<ColumnConfig> listCols = new ArrayList<ColumnConfig>();
    ColumnConfig col;

    RowNumberer rowNumberer = new RowNumberer();
    listCols.add( rowNumberer );

    col = new ColumnConfig();
    col.setId( COL_CONTEST_TYPE_ORDER );
    col.setWidth( 0 );
    col.setAlignment( HorizontalAlignment.RIGHT );
    col.setResizable( false );
    col.setHidden( true );
    col.setMenuDisabled( true );
    col.setSortable( false );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( COL_RESULT_TYPE );
    col.setHeader( constants.matchResultTypeAbbrev() );
    col.setToolTip( constants.matchResultType() );
    col.setWidth( 26 );
    col.setAlignment( HorizontalAlignment.CENTER );
    col.setResizable( false );
    col.setMenuDisabled( true );
    col.setSortable( true );
    col.setRenderer( renderer );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( COL_MATCHDAY_MOVEDAY_ID );
    col.setHeader( constants.movedayAbbrev() );
    col.setToolTip( constants.moveday() );
    col.setWidth( 26 );
    col.setAlignment( HorizontalAlignment.RIGHT );
    col.setResizable( false );
    col.setMenuDisabled( true );
    col.setSortable( true );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( COL_MATCH_ORDER );
    col.setHeader( constants.matchdayAbbrev() );
    col.setToolTip( constants.matchday() );
    col.setWidth( 26 );
    col.setAlignment( HorizontalAlignment.RIGHT );
    col.setResizable( false );
    col.setMenuDisabled( true );
    col.setSortable( true );
    col.setRenderer( renderer );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( COL_CONTEST_TYPE );
    col.setHeader( constants.contestTypeAbbrev() );
    col.setToolTip( constants.contestType() );
    col.setWidth( 26 );
    col.setAlignment( HorizontalAlignment.CENTER );
    col.setResizable( false );
    col.setMenuDisabled( true );
    col.setSortable( true );
    col.setRenderer( renderer );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "matchday_contestElement_contestRound_type_translated" );
    col.setHeader( constants.contestRound() );
    col.setWidth( 100 );
    col.setAlignment( HorizontalAlignment.LEFT );
    col.setResizable( true );
    col.setMenuDisabled( true );
    col.setSortable( true );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( COL_MATCH_TYPE );
    col.setHeader( constants.matchTypeAbbrev() );
    col.setToolTip( constants.matchType() );
    col.setWidth( 26 );
    col.setAlignment( HorizontalAlignment.CENTER );
    col.setResizable( false );
    col.setMenuDisabled( true );
    col.setSortable( true );
    col.setRenderer( renderer );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "clubOpponent_country" );
    col.setHeader( constants.countryAbbrev() );
    col.setToolTip( constants.country() );
    col.setWidth( 26 );
    col.setAlignment( HorizontalAlignment.CENTER );
    col.setResizable( false );
    col.setMenuDisabled( true );
    col.setSortable( false );
    col.setRenderer( renderer );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "clubOpponent_name" );
    col.setHeader( constants.opponentClub() );
    col.setWidth( 200 );
    col.setMenuDisabled( true );
    col.setSortable( false );
    col.setRenderer( renderer );
    listCols.add( col );

    col = new ColumnConfig();
    col.setId( "goalsThis" );
    col.setHeader( constants.result() );
    col.setWidth( 70 );
    col.setMenuDisabled( true );
    col.setSortable( false );
    col.setRenderer( renderer );
    listCols.add( col );

    final ColumnModel cm = new ColumnModel( listCols );

    // Header cells with tooltips
    //
    GroupingView view = new GroupingView();

    view.setForceFit( true );
    view.setGroupRenderer( new GridGroupRenderer() {
      @SuppressWarnings( "synthetic-access" )
      public String render( GroupColumnData data )
      {
        VHJsData matchFirst = (VHJsData) data.models.get( 0 );

        switch ( d_grouping )
        {
          case BY_CONTEST_TYPE:
          {
            VHJsContestType contestType = VHJsContestType.valueOf( matchFirst.getString( COL_CONTEST_TYPE ) );
            switch ( contestType )
            {
              case LEAGUE:
                return messages.clubDataLabelLeagueSituation( d_club.getString( "league_id_translated" ),
                    d_club.getInt( "league_category" ) );

              case CUP:
                return messages.clubDataLabelCupSituation( d_club.getString( "association_nationalCupId_translated" ) );

              case CL:
                return constants.championsLeague();

              case WL:
                return constants.worldLeague();

              default:
                return "Unsupported contest type: " + contestType.name();
            }
          }

          case BY_MOVEDAY:
          {
            if ( matchFirst.getDate( "moveday_date" ) != null )
              return VHMain.getMessages().movedayHeaderWithDate( matchFirst.getInt( "matchday_moveday_id" ),
                  matchFirst.getDate( "moveday_date" ) );

            return VHMain.getMessages().movedayHeader( matchFirst.getInt( "matchday_moveday_id" ) );
          }

          default:
          {
            return "Unsupported grouping type: " + d_grouping.name();
          }
        }
      }
    } );

    // Grid
    //
    d_grid = new Grid<VHJsData>( d_store, cm );
    d_grid.addPlugin( rowNumberer );
    d_grid.setView( view );
    d_grid.setAutoExpandColumn( "clubOpponent_name" );
    d_grid.setHideHeaders( false );
    d_grid.setStripeRows( true );
    d_grid.setBorders( true );
    d_grid.setAutoWidth( true );
  }
}
